from tensorflow import keras
from tensorflow.keras import layers
import pathlib
from tensorflow.keras.utils import image_dataset_from_directory
import pandas as pd
import pathlib
from pathlib import Path
import numpy as np
import pandas as pd
# plotting modules
from matplotlib import pyplot as plt
import seaborn as sns
from sklearn.model_selection import train_test_split
import plotly as plotly
plotly.offline.init_notebook_mode()
from tensorflow import keras
from tensorflow.keras import layers
import tensorflow as tf
from keras.utils import to_categorical
from keras.models import load_model
from PIL import Image
import plotly.graph_objects as go
from tensorflow.keras.models import Sequential
from keras.callbacks import ModelCheckpoint
from tensorflow.keras.layers import Dense
from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score, confusion_matrix, classification_report, precision_recall_curve, ConfusionMatrixDisplay
Framing the Problem¶
The purpose of this notebook is to help farmers and everyone really, to identify a plant using a picture of its leaf/leaves.
Getting the data¶
The dataset that we will be training our models on is gotten from Kaggle - https://www.kaggle.com/datasets/sadmansakibmahi/plant-disease-expert/data
data_folder = pathlib.Path("../../../../../../Downloads/datasets/plant-id")
def create_image_dataframe(folder):
data = {'ImagePath': [], 'ClassLabel': []}
for class_folder in folder.iterdir():
if class_folder.is_dir():
for img_path in class_folder.iterdir():
data['ImagePath'].append(img_path)
data['ClassLabel'].append(class_folder.name)
return pd.DataFrame(data)
df = create_image_dataframe(data_folder)
df
| ImagePath | ClassLabel | |
|---|---|---|
| 0 | ..\..\..\..\..\..\Downloads\datasets\plant-id\... | Apple |
| 1 | ..\..\..\..\..\..\Downloads\datasets\plant-id\... | Apple |
| 2 | ..\..\..\..\..\..\Downloads\datasets\plant-id\... | Apple |
| 3 | ..\..\..\..\..\..\Downloads\datasets\plant-id\... | Apple |
| 4 | ..\..\..\..\..\..\Downloads\datasets\plant-id\... | Apple |
| ... | ... | ... |
| 35375 | ..\..\..\..\..\..\Downloads\datasets\plant-id\... | Tomato |
| 35376 | ..\..\..\..\..\..\Downloads\datasets\plant-id\... | Tomato |
| 35377 | ..\..\..\..\..\..\Downloads\datasets\plant-id\... | Tomato |
| 35378 | ..\..\..\..\..\..\Downloads\datasets\plant-id\... | Tomato |
| 35379 | ..\..\..\..\..\..\Downloads\datasets\plant-id\... | Tomato |
35380 rows × 2 columns
As we can see from the above, we have 35,380 images in all the folders combined.
The class labels represent each of the folders we have in our downloaded folder.
len(df['ClassLabel'].unique())
10
We have 10 folders, which is the number of classes or plant species that we have in this dataset.
df['ClassLabel'].value_counts()
ClassLabel Grape 12345 Potato 4145 Apple 3948 Tomato 3819 Pepper bell 3549 Corn (maize) 2790 Cherry 2052 Strawberry 1511 Tea 861 Rice 360 Name: count, dtype: int64
Exploratory Data Analysis¶
Let us put our dataset to view.
import matplotlib.pyplot as plt
from PIL import Image
grouped = df.groupby('ClassLabel')
# Plot the first 5 images for each class
for label, group in grouped:
print(label)
print('=====================')
# Create a figure with 5 subplots (1 row, 5 columns)
fig, axes = plt.subplots(1, 5, figsize=(20, 4))
# Iterate over the first 5 rows of the group
for i in range(min(5, len(group))): # This ensures we don't go out of bounds if there are less than 5 images
img_path = group['ImagePath'].iloc[i]
img = Image.open(img_path)
# Plot the image in the i-th subplot
axes[i].imshow(img)
axes[i].set_title(label)
axes[i].axis('off')
# Hide any unused subplots if the group has less than 5 images
if len(group) < 5:
for j in range(len(group), 5):
axes[j].axis('off')
plt.show()
Apple =====================
Cherry =====================
Corn (maize) =====================
Grape =====================
Pepper bell =====================
Potato =====================
Rice =====================
Strawberry =====================
Tea =====================
Tomato =====================
Modeling¶
Before we train our model, we need to prepare our images to the format that the model expects.
df['ImagePath'] = df['ImagePath'].astype(str)
grouped = df.groupby('ClassLabel')
train_df = pd.DataFrame()
val_df = pd.DataFrame()
test_df = pd.DataFrame()
for _, group in grouped:
# Split into train and temporary test
train_tmp, test_tmp = train_test_split(group, test_size=0.3, random_state=42) # 70% train, 30% temp test
# Split the temporary test into actual validation and test
val_tmp, test_final = train_test_split(test_tmp, test_size=0.5, random_state=42) # Split 30% into 15% val, 15% test
# Append to the respective DataFrames
train_df = pd.concat([train_df, train_tmp])
val_df = pd.concat([val_df, val_tmp])
test_df = pd.concat([test_df, test_final])
# Now, you have train_df, val_df, and test_df
print(f"Training Set: {train_df.shape[0]} samples")
print(f"Validation Set: {val_df.shape[0]} samples")
print(f"Test Set: {test_df.shape[0]} samples")
Training Set: 24762 samples Validation Set: 5307 samples Test Set: 5311 samples
Here, we are applying some data augmentation to the dataset to help improve the performance of the model.
We apply some rotation to the images, move the width and heirght around a bit, also flipping them and inverting them.
Another very important step you can see below is that we have rescaled the rgb values of the images from 0 - 256 to values just between 0 and 1. This is an important step because it makes sure that the model doesn't assign more weights to the pixels with very high values.
from tensorflow.keras.preprocessing.image import ImageDataGenerator
def add_noise(image):
noise = tf.random.normal(shape=tf.shape(image), mean=0.0, stddev=0.05, dtype=tf.float32)
return image + noise
def color_jitter(image):
image = tf.image.random_hue(image, 0.08)
image = tf.image.random_saturation(image, 0.6, 1.6)
image = tf.image.random_brightness(image, 0.05)
image = tf.image.random_contrast(image, 0.7, 1.3)
return image
def resize_and_crop(image):
# Resize the image to a larger size to ensure we can crop properly
image = tf.image.resize(image, [180, 180])
# Randomly crop the image to the target size
image = tf.image.random_crop(image, size=[150, 150, 3])
return image
def preprocessing_function(image):
image = resize_and_crop(image)
image = add_noise(image)
image = color_jitter(image)
return image
train_datagen = ImageDataGenerator(
rescale=1./255,
rotation_range=30, # Randomly rotate images in the range (degrees, 0 to 180)
width_shift_range=0.2, # Randomly shift images horizontally (fraction of total width)
height_shift_range=0.2, # Randomly shift images vertically (fraction of total height)
zoom_range=0.2, # Randomly zoom images
brightness_range=[0.8, 1.2], # Randomly change brightness
horizontal_flip=True, # Randomly flip images horizontally
vertical_flip=True, # Randomly flip images vertically
preprocessing_function=preprocessing_function # Custom preprocessing
)
val_datagen = ImageDataGenerator(rescale=1./255)
train_generator = train_datagen.flow_from_dataframe(
dataframe=train_df,
x_col="ImagePath",
y_col="ClassLabel",
batch_size=32,
seed=42,
shuffle=True,
class_mode="categorical",
target_size=(150,150))
valid_generator = val_datagen.flow_from_dataframe(
dataframe=val_df,
x_col="ImagePath",
y_col="ClassLabel",
batch_size=32,
seed=42,
shuffle=True,
class_mode="categorical",
target_size=(150,150))
test_generator = val_datagen.flow_from_dataframe(
dataframe=test_df,
x_col="ImagePath",
y_col="ClassLabel",
batch_size=32,
seed=42,
shuffle=False,
class_mode="categorical",
target_size=(150,150))
Found 24762 validated image filenames belonging to 10 classes. Found 5307 validated image filenames belonging to 10 classes. Found 5311 validated image filenames belonging to 10 classes.
Convolutional Neural Network Model¶
With tensorflow and keras, we will be using a fully connected neural network for our model.
from tensorflow import keras
from tensorflow.keras import layers
inputs = keras.Input(shape=(150, 150, 3))
x = layers.Conv2D(filters=32, kernel_size=3, activation="relu")(inputs)
x = layers.MaxPooling2D(pool_size=2)(x)
x = layers.Conv2D(filters=64, kernel_size=3, activation="relu")(x)
x = layers.MaxPooling2D(pool_size=2)(x)
x = layers.Conv2D(filters=128, kernel_size=3, activation="relu")(x)
x = layers.MaxPooling2D(pool_size=2)(x)
x = layers.Conv2D(filters=256, kernel_size=3, activation="relu")(x)
x = layers.MaxPooling2D(pool_size=2)(x)
x = layers.Conv2D(filters=256, kernel_size=3, activation="relu")(x)
x = layers.Flatten()(x)
outputs = layers.Dense(10, activation="softmax")(x) #
model = keras.Model(inputs=inputs, outputs=outputs)
Model Explainability¶
Model Architecture and Training Overview¶
We've constructed a neural network model using TensorFlow and Keras, designed specifically for image classification. This model processes images sized 150x150 pixels with 3 color channels (RGB).
Model Layers:
The model starts with a series of convolutional layers, where each layer is designed to detect specific features in the image like edges, textures, or more complex patterns as we go deeper.
Each convolutional layer is followed by a max-pooling layer, which reduces the spatial dimensions of the image representations, helping to make the detection of features invariant to scale and orientation changes.
After multiple layers of convolutions and pooling, the high-level understanding of the images is flattened into a vector that serves as input to a fully connected layer.
Output Layer:
The final layer is a dense layer with 10 units, corresponding to the number of categories we want to classify. It uses the softmax activation function to output probabilities for each class, indicating the likelihood of the image belonging to each class.
Model Compilation:
The model uses the Adam optimizer for adjusting weights, which is effective and efficient for this kind of problem. It minimizes a function called categorical crossentropy, a common choice for classification tasks, which measures the difference between the predicted probabilities and the actual distribution of the labels. We track the accuracy during training as a straightforward metric to understand how well the model performs.
Training Process Enhancements¶
To optimize training and avoid common pitfalls:
ModelCheckpoint: Saves the best model as we train, ensuring that we always have the version of the model that performed best on the validation set, in case later iterations perform worse.
EarlyStopping: Monitors the model's performance on a validation set and stops training if the model's performance doesn't improve for 10 consecutive epochs. This prevents overfitting and unnecessary computation by stopping when the model isn't learning anymore.
ReduceLROnPlateau: Reduces the learning rate if the validation loss stops improving. Smaller steps in weight updates can lead to better fine-tuning and better overall model performance.
Execution¶
The model is trained using the specified training and validation datasets for 15 epochs, but training can stop early if no improvement is seen as monitored by our callbacks. This setup ensures that the training is both efficient and effective, adapting to the data as needed.
model.summary()
Model: "model_4"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
input_5 (InputLayer) [(None, 150, 150, 3)] 0
conv2d_99 (Conv2D) (None, 148, 148, 32) 896
max_pooling2d_8 (MaxPooling (None, 74, 74, 32) 0
2D)
conv2d_100 (Conv2D) (None, 72, 72, 64) 18496
max_pooling2d_9 (MaxPooling (None, 36, 36, 64) 0
2D)
conv2d_101 (Conv2D) (None, 34, 34, 128) 73856
max_pooling2d_10 (MaxPoolin (None, 17, 17, 128) 0
g2D)
conv2d_102 (Conv2D) (None, 15, 15, 256) 295168
max_pooling2d_11 (MaxPoolin (None, 7, 7, 256) 0
g2D)
conv2d_103 (Conv2D) (None, 5, 5, 256) 590080
flatten_1 (Flatten) (None, 6400) 0
dense_7 (Dense) (None, 10) 64010
=================================================================
Total params: 1,042,506
Trainable params: 1,042,506
Non-trainable params: 0
_________________________________________________________________
model.compile(
optimizer='adam',
loss='categorical_crossentropy',
metrics=['accuracy']
)
# Define callbacks
from tensorflow.keras import optimizers, callbacks
my_callbacks = [
callbacks.ModelCheckpoint(filepath='./models/newer/vanilla.h5', save_best_only=True),
callbacks.EarlyStopping(monitor='val_loss', patience=10, verbose=1),
callbacks.ReduceLROnPlateau(monitor='val_loss', factor=0.2, patience=5, verbose=1, min_lr=1e-5)
]
history = model.fit(
train_generator,
validation_data=valid_generator,
epochs=30,
callbacks=my_callbacks
)
Epoch 1/30 774/774 [==============================] - 1095s 1s/step - loss: 1.3464 - accuracy: 0.5453 - val_loss: 2.2064 - val_accuracy: 0.4536 - lr: 0.0010 Epoch 2/30 774/774 [==============================] - 1919s 2s/step - loss: 0.6518 - accuracy: 0.7783 - val_loss: 1.7659 - val_accuracy: 0.6514 - lr: 0.0010 Epoch 3/30 774/774 [==============================] - 315s 407ms/step - loss: 0.4234 - accuracy: 0.8592 - val_loss: 0.7866 - val_accuracy: 0.8059 - lr: 0.0010 Epoch 4/30 774/774 [==============================] - 297s 384ms/step - loss: 0.3322 - accuracy: 0.8910 - val_loss: 0.5070 - val_accuracy: 0.8660 - lr: 0.0010 Epoch 5/30 774/774 [==============================] - 298s 385ms/step - loss: 0.2633 - accuracy: 0.9139 - val_loss: 0.2042 - val_accuracy: 0.9335 - lr: 0.0010 Epoch 6/30 774/774 [==============================] - 295s 381ms/step - loss: 0.2423 - accuracy: 0.9215 - val_loss: 0.6220 - val_accuracy: 0.8681 - lr: 0.0010 Epoch 7/30 774/774 [==============================] - 295s 381ms/step - loss: 0.2083 - accuracy: 0.9331 - val_loss: 0.4237 - val_accuracy: 0.8852 - lr: 0.0010 Epoch 8/30 774/774 [==============================] - 295s 382ms/step - loss: 0.1835 - accuracy: 0.9408 - val_loss: 0.1222 - val_accuracy: 0.9668 - lr: 0.0010 Epoch 9/30 774/774 [==============================] - 297s 383ms/step - loss: 0.1774 - accuracy: 0.9439 - val_loss: 0.2264 - val_accuracy: 0.9378 - lr: 0.0010 Epoch 10/30 774/774 [==============================] - 297s 383ms/step - loss: 0.1584 - accuracy: 0.9487 - val_loss: 0.1706 - val_accuracy: 0.9508 - lr: 0.0010 Epoch 11/30 774/774 [==============================] - 294s 380ms/step - loss: 0.1477 - accuracy: 0.9534 - val_loss: 0.1628 - val_accuracy: 0.9542 - lr: 0.0010 Epoch 12/30 774/774 [==============================] - 296s 382ms/step - loss: 0.1445 - accuracy: 0.9536 - val_loss: 0.1516 - val_accuracy: 0.9563 - lr: 0.0010 Epoch 13/30 774/774 [==============================] - ETA: 0s - loss: 0.1306 - accuracy: 0.9593 Epoch 13: ReduceLROnPlateau reducing learning rate to 0.00020000000949949026. 774/774 [==============================] - 299s 386ms/step - loss: 0.1306 - accuracy: 0.9593 - val_loss: 0.1493 - val_accuracy: 0.9578 - lr: 0.0010 Epoch 14/30 774/774 [==============================] - 299s 386ms/step - loss: 0.0664 - accuracy: 0.9782 - val_loss: 0.0628 - val_accuracy: 0.9796 - lr: 2.0000e-04 Epoch 15/30 774/774 [==============================] - 297s 383ms/step - loss: 0.0571 - accuracy: 0.9812 - val_loss: 0.1513 - val_accuracy: 0.9557 - lr: 2.0000e-04 Epoch 16/30 774/774 [==============================] - 296s 382ms/step - loss: 0.0571 - accuracy: 0.9815 - val_loss: 0.1062 - val_accuracy: 0.9685 - lr: 2.0000e-04 Epoch 17/30 774/774 [==============================] - 297s 384ms/step - loss: 0.0495 - accuracy: 0.9834 - val_loss: 0.0724 - val_accuracy: 0.9785 - lr: 2.0000e-04 Epoch 18/30 774/774 [==============================] - 297s 384ms/step - loss: 0.0509 - accuracy: 0.9840 - val_loss: 0.0889 - val_accuracy: 0.9717 - lr: 2.0000e-04 Epoch 19/30 774/774 [==============================] - 296s 382ms/step - loss: 0.0494 - accuracy: 0.9843 - val_loss: 0.0396 - val_accuracy: 0.9872 - lr: 2.0000e-04 Epoch 20/30 774/774 [==============================] - 295s 381ms/step - loss: 0.0450 - accuracy: 0.9857 - val_loss: 0.0523 - val_accuracy: 0.9838 - lr: 2.0000e-04 Epoch 21/30 774/774 [==============================] - 297s 383ms/step - loss: 0.0461 - accuracy: 0.9862 - val_loss: 0.0728 - val_accuracy: 0.9776 - lr: 2.0000e-04 Epoch 22/30 774/774 [==============================] - 299s 386ms/step - loss: 0.0461 - accuracy: 0.9853 - val_loss: 0.0637 - val_accuracy: 0.9815 - lr: 2.0000e-04 Epoch 23/30 774/774 [==============================] - 300s 387ms/step - loss: 0.0428 - accuracy: 0.9864 - val_loss: 0.0921 - val_accuracy: 0.9744 - lr: 2.0000e-04 Epoch 24/30 774/774 [==============================] - ETA: 0s - loss: 0.0449 - accuracy: 0.9858 Epoch 24: ReduceLROnPlateau reducing learning rate to 4.0000001899898055e-05. 774/774 [==============================] - 304s 393ms/step - loss: 0.0449 - accuracy: 0.9858 - val_loss: 0.1405 - val_accuracy: 0.9612 - lr: 2.0000e-04 Epoch 25/30 774/774 [==============================] - 307s 396ms/step - loss: 0.0325 - accuracy: 0.9896 - val_loss: 0.0602 - val_accuracy: 0.9804 - lr: 4.0000e-05 Epoch 26/30 774/774 [==============================] - 304s 393ms/step - loss: 0.0278 - accuracy: 0.9912 - val_loss: 0.0841 - val_accuracy: 0.9753 - lr: 4.0000e-05 Epoch 27/30 774/774 [==============================] - 304s 393ms/step - loss: 0.0288 - accuracy: 0.9897 - val_loss: 0.0856 - val_accuracy: 0.9740 - lr: 4.0000e-05 Epoch 28/30 774/774 [==============================] - 308s 398ms/step - loss: 0.0320 - accuracy: 0.9897 - val_loss: 0.0748 - val_accuracy: 0.9761 - lr: 4.0000e-05 Epoch 29/30 774/774 [==============================] - ETA: 0s - loss: 0.0289 - accuracy: 0.9911 Epoch 29: ReduceLROnPlateau reducing learning rate to 1e-05. 774/774 [==============================] - 309s 399ms/step - loss: 0.0289 - accuracy: 0.9911 - val_loss: 0.0751 - val_accuracy: 0.9768 - lr: 4.0000e-05 Epoch 29: early stopping
history_df = pd.DataFrame(history.history)
history_df.insert(0, 'epoch', range(1, len(history_df) + 1))
history_df
| epoch | loss | accuracy | val_loss | val_accuracy | lr | |
|---|---|---|---|---|---|---|
| 0 | 1 | 1.346362 | 0.545271 | 2.206433 | 0.453552 | 0.00100 |
| 1 | 2 | 0.651767 | 0.778289 | 1.765861 | 0.651404 | 0.00100 |
| 2 | 3 | 0.423353 | 0.859179 | 0.786587 | 0.805917 | 0.00100 |
| 3 | 4 | 0.332164 | 0.891043 | 0.507010 | 0.866026 | 0.00100 |
| 4 | 5 | 0.263335 | 0.913900 | 0.204228 | 0.933484 | 0.00100 |
| 5 | 6 | 0.242320 | 0.921533 | 0.622015 | 0.868099 | 0.00100 |
| 6 | 7 | 0.208308 | 0.933123 | 0.423699 | 0.885246 | 0.00100 |
| 7 | 8 | 0.183510 | 0.940837 | 0.122238 | 0.966836 | 0.00100 |
| 8 | 9 | 0.177364 | 0.943946 | 0.226416 | 0.937818 | 0.00100 |
| 9 | 10 | 0.158361 | 0.948671 | 0.170555 | 0.950820 | 0.00100 |
| 10 | 11 | 0.147676 | 0.953437 | 0.162780 | 0.954211 | 0.00100 |
| 11 | 12 | 0.144481 | 0.953598 | 0.151577 | 0.956284 | 0.00100 |
| 12 | 13 | 0.130632 | 0.959252 | 0.149276 | 0.957792 | 0.00100 |
| 13 | 14 | 0.066417 | 0.978192 | 0.062791 | 0.979650 | 0.00020 |
| 14 | 15 | 0.057136 | 0.981221 | 0.151331 | 0.955719 | 0.00020 |
| 15 | 16 | 0.057144 | 0.981544 | 0.106232 | 0.968532 | 0.00020 |
| 16 | 17 | 0.049510 | 0.983402 | 0.072435 | 0.978519 | 0.00020 |
| 17 | 18 | 0.050905 | 0.983967 | 0.088898 | 0.971735 | 0.00020 |
| 18 | 19 | 0.049367 | 0.984331 | 0.039642 | 0.987187 | 0.00020 |
| 19 | 20 | 0.044987 | 0.985664 | 0.052274 | 0.983795 | 0.00020 |
| 20 | 21 | 0.046138 | 0.986189 | 0.072773 | 0.977577 | 0.00020 |
| 21 | 22 | 0.046072 | 0.985260 | 0.063689 | 0.981534 | 0.00020 |
| 22 | 23 | 0.042846 | 0.986390 | 0.092071 | 0.974373 | 0.00020 |
| 23 | 24 | 0.044919 | 0.985785 | 0.140496 | 0.961183 | 0.00020 |
| 24 | 25 | 0.032528 | 0.989621 | 0.060175 | 0.980403 | 0.00004 |
| 25 | 26 | 0.027804 | 0.991196 | 0.084115 | 0.975316 | 0.00004 |
| 26 | 27 | 0.028785 | 0.989702 | 0.085557 | 0.973997 | 0.00004 |
| 27 | 28 | 0.031960 | 0.989702 | 0.074788 | 0.976069 | 0.00004 |
| 28 | 29 | 0.028948 | 0.991075 | 0.075122 | 0.976823 | 0.00004 |
# Create a DataFrame from the history object
history_df = pd.DataFrame(history.history)
# Plot the training and validation loss
plt.figure(figsize=(9, 5))
values = history_df['accuracy']
epochs = range(1, len(values) + 1)
plt.plot(epochs, history_df['loss'], 'bo', label='Training loss')
plt.plot(epochs, history_df['val_loss'], 'ro', label='Validation loss')
plt.xlabel('Epochs')
plt.xticks(epochs)
plt.ylabel('Loss')
plt.legend()
plt.title('Training and validation loss')
plt.show()
# Plot the training and validation accuracy
plt.figure(figsize=(9, 5))
plt.plot(epochs, history_df['accuracy'], 'bo', label='Training accuracy')
plt.plot(epochs, history_df['val_accuracy'], 'ro', label='Validation accuracy')
plt.xlabel('Epochs')
plt.xticks(epochs)
plt.ylabel('Accuracy')
plt.legend()
plt.title('Training and validation accuracy')
plt.show()
Interpreting the Model Performance¶
After training the model over 30 epochs, we were able to get an accuracy score of 99.9% on our validation dataset.
Evaluating the Model on the Test Data¶
# evaluate the model
model.evaluate(test_generator)
166/166 [==============================] - 12s 74ms/step - loss: 0.0686 - accuracy: 0.9814
[0.06857447326183319, 0.9813594222068787]
# predict the model
y_pred = model.predict(test_generator)
# get the class with the highest probability
y_pred_labels = np.argmax(y_pred, axis=1)
# get the true class
y_true = np.array(test_generator.classes)
# get the class labels
class_labels = list(test_generator.class_indices.keys())
# get the accuracy
accuracy = accuracy_score(y_true, y_pred_labels)
print(f'Accuracy: {accuracy}')
166/166 [==============================] - 9s 54ms/step Accuracy: 0.9813594426661646
print(classification_report(y_true, y_pred_labels, target_names=class_labels, zero_division=0))
precision recall f1-score support
Apple 0.95 1.00 0.98 593
Cherry 0.93 1.00 0.96 308
Corn (maize) 1.00 1.00 1.00 419
Grape 1.00 0.99 0.99 1852
Pepper bell 1.00 0.93 0.96 533
Potato 0.97 0.98 0.97 622
Rice 1.00 0.94 0.97 54
Strawberry 0.93 0.94 0.93 227
Tea 0.99 1.00 1.00 130
Tomato 0.98 0.99 0.98 573
accuracy 0.98 5311
macro avg 0.98 0.98 0.98 5311
weighted avg 0.98 0.98 0.98 5311
Above, we can see how the model performed. We have an accuracy of 99.8% on the test data. And then we can also see how it performed on each class.
# model.save('./models/new/plant-disease-vanilla.h5')
Future Work¶
from tensorflow.keras.applications import VGG16
from tensorflow.keras.models import Model
from tensorflow.keras.layers import Dense, Flatten, GlobalAveragePooling2D
vgg_model = VGG16(weights='imagenet', include_top=False, input_shape=(150, 150, 3))
# Freeze the base model
vgg_model.trainable = False
# Add custom layers on top of the base model
x = vgg_model.output
x = GlobalAveragePooling2D()(x)
x = Dense(512, activation='relu')(x)
predictions = Dense(10, activation='softmax')(x)
# Create the model
model = Model(inputs=vgg_model.input, outputs=predictions)
# Compile the model
model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])
vgg_callbacks = [
callbacks.ModelCheckpoint(filepath='./models/newer/vgg16_vanilla.h5', save_best_only=True),
callbacks.EarlyStopping(monitor='val_loss', patience=10, verbose=1),
callbacks.ReduceLROnPlateau(monitor='val_loss', factor=0.2, patience=5, verbose=1, min_lr=1e-5)
]
# Training the model
history = model.fit(train_generator, validation_data=valid_generator, epochs=30, callbacks=vgg_callbacks)
Epoch 1/30 774/774 [==============================] - 331s 425ms/step - loss: 0.4735 - accuracy: 0.8503 - val_loss: 0.1455 - val_accuracy: 0.9550 - lr: 0.0010 Epoch 2/30 774/774 [==============================] - 332s 429ms/step - loss: 0.2484 - accuracy: 0.9174 - val_loss: 0.1095 - val_accuracy: 0.9653 - lr: 0.0010 Epoch 3/30 774/774 [==============================] - 331s 428ms/step - loss: 0.2110 - accuracy: 0.9294 - val_loss: 0.0991 - val_accuracy: 0.9672 - lr: 0.0010 Epoch 4/30 774/774 [==============================] - 330s 426ms/step - loss: 0.1963 - accuracy: 0.9348 - val_loss: 0.0828 - val_accuracy: 0.9746 - lr: 0.0010 Epoch 5/30 774/774 [==============================] - 332s 429ms/step - loss: 0.1818 - accuracy: 0.9398 - val_loss: 0.0913 - val_accuracy: 0.9697 - lr: 0.0010 Epoch 6/30 774/774 [==============================] - 332s 429ms/step - loss: 0.1761 - accuracy: 0.9410 - val_loss: 0.0843 - val_accuracy: 0.9742 - lr: 0.0010 Epoch 7/30 774/774 [==============================] - 333s 431ms/step - loss: 0.1645 - accuracy: 0.9433 - val_loss: 0.0831 - val_accuracy: 0.9706 - lr: 0.0010 Epoch 8/30 774/774 [==============================] - 335s 432ms/step - loss: 0.1659 - accuracy: 0.9431 - val_loss: 0.1222 - val_accuracy: 0.9568 - lr: 0.0010 Epoch 9/30 774/774 [==============================] - 340s 439ms/step - loss: 0.1612 - accuracy: 0.9456 - val_loss: 0.0687 - val_accuracy: 0.9772 - lr: 0.0010 Epoch 10/30 774/774 [==============================] - 339s 438ms/step - loss: 0.1470 - accuracy: 0.9488 - val_loss: 0.0780 - val_accuracy: 0.9734 - lr: 0.0010 Epoch 11/30 774/774 [==============================] - 339s 438ms/step - loss: 0.1465 - accuracy: 0.9501 - val_loss: 0.0568 - val_accuracy: 0.9821 - lr: 0.0010 Epoch 12/30 774/774 [==============================] - 362s 468ms/step - loss: 0.1461 - accuracy: 0.9505 - val_loss: 0.0613 - val_accuracy: 0.9813 - lr: 0.0010 Epoch 13/30 774/774 [==============================] - 342s 442ms/step - loss: 0.1409 - accuracy: 0.9509 - val_loss: 0.0659 - val_accuracy: 0.9766 - lr: 0.0010 Epoch 14/30 774/774 [==============================] - 341s 441ms/step - loss: 0.1357 - accuracy: 0.9529 - val_loss: 0.0790 - val_accuracy: 0.9734 - lr: 0.0010 Epoch 15/30 774/774 [==============================] - 343s 443ms/step - loss: 0.1297 - accuracy: 0.9543 - val_loss: 0.0589 - val_accuracy: 0.9821 - lr: 0.0010 Epoch 16/30 774/774 [==============================] - ETA: 0s - loss: 0.1339 - accuracy: 0.9549 Epoch 16: ReduceLROnPlateau reducing learning rate to 0.00020000000949949026. 774/774 [==============================] - 343s 443ms/step - loss: 0.1339 - accuracy: 0.9549 - val_loss: 0.0652 - val_accuracy: 0.9793 - lr: 0.0010 Epoch 17/30 774/774 [==============================] - 347s 448ms/step - loss: 0.1103 - accuracy: 0.9624 - val_loss: 0.0553 - val_accuracy: 0.9810 - lr: 2.0000e-04 Epoch 18/30 774/774 [==============================] - 347s 449ms/step - loss: 0.1033 - accuracy: 0.9652 - val_loss: 0.0580 - val_accuracy: 0.9812 - lr: 2.0000e-04 Epoch 19/30 774/774 [==============================] - 351s 454ms/step - loss: 0.1027 - accuracy: 0.9647 - val_loss: 0.0568 - val_accuracy: 0.9787 - lr: 2.0000e-04 Epoch 20/30 774/774 [==============================] - 349s 451ms/step - loss: 0.1083 - accuracy: 0.9629 - val_loss: 0.0512 - val_accuracy: 0.9830 - lr: 2.0000e-04 Epoch 21/30 774/774 [==============================] - 351s 453ms/step - loss: 0.1038 - accuracy: 0.9658 - val_loss: 0.0600 - val_accuracy: 0.9781 - lr: 2.0000e-04 Epoch 22/30 774/774 [==============================] - 354s 457ms/step - loss: 0.0987 - accuracy: 0.9672 - val_loss: 0.0586 - val_accuracy: 0.9800 - lr: 2.0000e-04 Epoch 23/30 774/774 [==============================] - 357s 462ms/step - loss: 0.1025 - accuracy: 0.9653 - val_loss: 0.0621 - val_accuracy: 0.9804 - lr: 2.0000e-04 Epoch 24/30 774/774 [==============================] - 359s 464ms/step - loss: 0.1032 - accuracy: 0.9639 - val_loss: 0.0548 - val_accuracy: 0.9804 - lr: 2.0000e-04 Epoch 25/30 774/774 [==============================] - ETA: 0s - loss: 0.1033 - accuracy: 0.9633 Epoch 25: ReduceLROnPlateau reducing learning rate to 4.0000001899898055e-05. 774/774 [==============================] - 358s 463ms/step - loss: 0.1033 - accuracy: 0.9633 - val_loss: 0.0572 - val_accuracy: 0.9813 - lr: 2.0000e-04 Epoch 26/30 774/774 [==============================] - 359s 464ms/step - loss: 0.0968 - accuracy: 0.9665 - val_loss: 0.0497 - val_accuracy: 0.9825 - lr: 4.0000e-05 Epoch 27/30 774/774 [==============================] - 362s 467ms/step - loss: 0.0950 - accuracy: 0.9675 - val_loss: 0.0510 - val_accuracy: 0.9827 - lr: 4.0000e-05 Epoch 28/30 774/774 [==============================] - 360s 465ms/step - loss: 0.0982 - accuracy: 0.9654 - val_loss: 0.0506 - val_accuracy: 0.9834 - lr: 4.0000e-05 Epoch 29/30 774/774 [==============================] - 358s 463ms/step - loss: 0.0966 - accuracy: 0.9664 - val_loss: 0.0501 - val_accuracy: 0.9829 - lr: 4.0000e-05 Epoch 30/30 774/774 [==============================] - 355s 459ms/step - loss: 0.0946 - accuracy: 0.9671 - val_loss: 0.0513 - val_accuracy: 0.9815 - lr: 4.0000e-05
history_df = pd.DataFrame(history.history)
history_df.insert(0, 'epoch', range(1, len(history_df) + 1))
history_df
| epoch | loss | accuracy | val_loss | val_accuracy | lr | |
|---|---|---|---|---|---|---|
| 0 | 1 | 0.473496 | 0.850335 | 0.145496 | 0.954965 | 0.00100 |
| 1 | 2 | 0.248432 | 0.917373 | 0.109509 | 0.965329 | 0.00100 |
| 2 | 3 | 0.211032 | 0.929408 | 0.099066 | 0.967213 | 0.00100 |
| 3 | 4 | 0.196292 | 0.934819 | 0.082777 | 0.974562 | 0.00100 |
| 4 | 5 | 0.181791 | 0.939787 | 0.091314 | 0.969663 | 0.00100 |
| 5 | 6 | 0.176082 | 0.940998 | 0.084296 | 0.974185 | 0.00100 |
| 6 | 7 | 0.164489 | 0.943341 | 0.083059 | 0.970605 | 0.00100 |
| 7 | 8 | 0.165904 | 0.943098 | 0.122178 | 0.956849 | 0.00100 |
| 8 | 9 | 0.161170 | 0.945562 | 0.068655 | 0.977200 | 0.00100 |
| 9 | 10 | 0.147003 | 0.948793 | 0.078003 | 0.973431 | 0.00100 |
| 10 | 11 | 0.146516 | 0.950085 | 0.056824 | 0.982099 | 0.00100 |
| 11 | 12 | 0.146131 | 0.950489 | 0.061275 | 0.981345 | 0.00100 |
| 12 | 13 | 0.140935 | 0.950852 | 0.065926 | 0.976635 | 0.00100 |
| 13 | 14 | 0.135654 | 0.952871 | 0.079004 | 0.973431 | 0.00100 |
| 14 | 15 | 0.129676 | 0.954325 | 0.058877 | 0.982099 | 0.00100 |
| 15 | 16 | 0.133877 | 0.954931 | 0.065177 | 0.979273 | 0.00100 |
| 16 | 17 | 0.110282 | 0.962362 | 0.055346 | 0.980969 | 0.00020 |
| 17 | 18 | 0.103291 | 0.965229 | 0.058031 | 0.981157 | 0.00020 |
| 18 | 19 | 0.102651 | 0.964704 | 0.056849 | 0.978707 | 0.00020 |
| 19 | 20 | 0.108301 | 0.962887 | 0.051188 | 0.983041 | 0.00020 |
| 20 | 21 | 0.103799 | 0.965794 | 0.059951 | 0.978142 | 0.00020 |
| 21 | 22 | 0.098665 | 0.967167 | 0.058564 | 0.980026 | 0.00020 |
| 22 | 23 | 0.102459 | 0.965269 | 0.062096 | 0.980403 | 0.00020 |
| 23 | 24 | 0.103229 | 0.963856 | 0.054762 | 0.980403 | 0.00020 |
| 24 | 25 | 0.103273 | 0.963291 | 0.057197 | 0.981345 | 0.00020 |
| 25 | 26 | 0.096757 | 0.966481 | 0.049681 | 0.982476 | 0.00004 |
| 26 | 27 | 0.094969 | 0.967531 | 0.051033 | 0.982664 | 0.00004 |
| 27 | 28 | 0.098184 | 0.965431 | 0.050577 | 0.983418 | 0.00004 |
| 28 | 29 | 0.096563 | 0.966400 | 0.050056 | 0.982853 | 0.00004 |
| 29 | 30 | 0.094638 | 0.967127 | 0.051328 | 0.981534 | 0.00004 |
# Create a DataFrame from the history object
history_df = pd.DataFrame(history.history)
# Plot the training and validation loss
plt.figure(figsize=(9, 5))
values = history_df['accuracy']
epochs = range(1, len(values) + 1)
plt.plot(epochs, history_df['loss'], 'bo', label='Training loss')
plt.plot(epochs, history_df['val_loss'], 'ro', label='Validation loss')
plt.xlabel('Epochs')
plt.xticks(epochs)
plt.ylabel('Loss')
plt.legend()
plt.title('Training and validation loss')
plt.show()
# Plot the training and validation accuracy
plt.figure(figsize=(9, 5))
plt.plot(epochs, history_df['accuracy'], 'bo', label='Training accuracy')
plt.plot(epochs, history_df['val_accuracy'], 'ro', label='Validation accuracy')
plt.xlabel('Epochs')
plt.xticks(epochs)
plt.ylabel('Accuracy')
plt.legend()
plt.title('Training and validation accuracy')
plt.show()
# evaluate the model
model.evaluate(test_generator)
166/166 [==============================] - 15s 87ms/step - loss: 0.0451 - accuracy: 0.9840
[0.045121122151613235, 0.9839954972267151]
from tensorflow.keras.applications import ResNet50
resnet_model = ResNet50(weights='imagenet', include_top=False, input_shape=(150, 150, 3))
# Freeze the base model
resnet_model.trainable = False
# Add custom layers on top of the base model
x = resnet_model.output
x = GlobalAveragePooling2D()(x)
x = Dense(512, activation='relu')(x)
predictions = Dense(10, activation='softmax')(x)
# Create the model
model = Model(inputs=resnet_model.input, outputs=predictions)
# Compile the model
model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])
resnet_callbacks = [
callbacks.ModelCheckpoint(filepath='./models/newer/resnet.h5', save_best_only=True),
callbacks.EarlyStopping(monitor='val_loss', patience=10, verbose=1),
callbacks.ReduceLROnPlateau(monitor='val_loss', factor=0.2, patience=5, verbose=1, min_lr=1e-5)
]
# Training the model
history = model.fit(train_generator, validation_data=valid_generator, epochs=30, callbacks=resnet_callbacks)
Epoch 1/30 774/774 [==============================] - 358s 459ms/step - loss: 1.9210 - accuracy: 0.3603 - val_loss: 1.8186 - val_accuracy: 0.4341 - lr: 0.0010 Epoch 2/30 774/774 [==============================] - 357s 461ms/step - loss: 1.7845 - accuracy: 0.3877 - val_loss: 1.5984 - val_accuracy: 0.4113 - lr: 0.0010 Epoch 3/30 774/774 [==============================] - 355s 458ms/step - loss: 1.6830 - accuracy: 0.4166 - val_loss: 1.4394 - val_accuracy: 0.5031 - lr: 0.0010 Epoch 4/30 774/774 [==============================] - 357s 461ms/step - loss: 1.5690 - accuracy: 0.4568 - val_loss: 1.3823 - val_accuracy: 0.5483 - lr: 0.0010 Epoch 5/30 774/774 [==============================] - 357s 461ms/step - loss: 1.4822 - accuracy: 0.4914 - val_loss: 1.2077 - val_accuracy: 0.6243 - lr: 0.0010 Epoch 6/30 774/774 [==============================] - 352s 455ms/step - loss: 1.4092 - accuracy: 0.5166 - val_loss: 1.2771 - val_accuracy: 0.5753 - lr: 0.0010 Epoch 7/30 774/774 [==============================] - 358s 462ms/step - loss: 1.3472 - accuracy: 0.5403 - val_loss: 1.3529 - val_accuracy: 0.5432 - lr: 0.0010 Epoch 8/30 774/774 [==============================] - 360s 465ms/step - loss: 1.3016 - accuracy: 0.5565 - val_loss: 1.3384 - val_accuracy: 0.5613 - lr: 0.0010 Epoch 9/30 774/774 [==============================] - 349s 451ms/step - loss: 1.2843 - accuracy: 0.5609 - val_loss: 1.2331 - val_accuracy: 0.6007 - lr: 0.0010 Epoch 10/30 774/774 [==============================] - ETA: 0s - loss: 1.2398 - accuracy: 0.5767 Epoch 10: ReduceLROnPlateau reducing learning rate to 0.00020000000949949026. 774/774 [==============================] - 535s 692ms/step - loss: 1.2398 - accuracy: 0.5767 - val_loss: 1.2863 - val_accuracy: 0.5719 - lr: 0.0010 Epoch 11/30 774/774 [==============================] - 599s 773ms/step - loss: 1.1618 - accuracy: 0.6092 - val_loss: 1.2851 - val_accuracy: 0.5824 - lr: 2.0000e-04 Epoch 12/30 774/774 [==============================] - 5608s 7s/step - loss: 1.1628 - accuracy: 0.6084 - val_loss: 1.3966 - val_accuracy: 0.5338 - lr: 2.0000e-04 Epoch 13/30 774/774 [==============================] - 682s 880ms/step - loss: 1.1558 - accuracy: 0.6117 - val_loss: 1.4318 - val_accuracy: 0.5293 - lr: 2.0000e-04 Epoch 14/30 774/774 [==============================] - 292s 378ms/step - loss: 1.1432 - accuracy: 0.6140 - val_loss: 1.4195 - val_accuracy: 0.5267 - lr: 2.0000e-04 Epoch 15/30 774/774 [==============================] - ETA: 0s - loss: 1.1404 - accuracy: 0.6171 Epoch 15: ReduceLROnPlateau reducing learning rate to 4.0000001899898055e-05. 774/774 [==============================] - 291s 376ms/step - loss: 1.1404 - accuracy: 0.6171 - val_loss: 1.4003 - val_accuracy: 0.5466 - lr: 2.0000e-04 Epoch 15: early stopping
history_df = pd.DataFrame(history.history)
history_df.insert(0, 'epoch', range(1, len(history_df) + 1))
history_df
| epoch | loss | accuracy | val_loss | val_accuracy | lr | |
|---|---|---|---|---|---|---|
| 0 | 1 | 1.921015 | 0.360270 | 1.818613 | 0.434144 | 0.0010 |
| 1 | 2 | 1.784497 | 0.387731 | 1.598449 | 0.411344 | 0.0010 |
| 2 | 3 | 1.682990 | 0.416646 | 1.439388 | 0.503109 | 0.0010 |
| 3 | 4 | 1.569026 | 0.456829 | 1.382310 | 0.548332 | 0.0010 |
| 4 | 5 | 1.482225 | 0.491358 | 1.207664 | 0.624270 | 0.0010 |
| 5 | 6 | 1.409242 | 0.516598 | 1.277117 | 0.575278 | 0.0010 |
| 6 | 7 | 1.347218 | 0.540263 | 1.352898 | 0.543245 | 0.0010 |
| 7 | 8 | 1.301566 | 0.556538 | 1.338384 | 0.561334 | 0.0010 |
| 8 | 9 | 1.284263 | 0.560940 | 1.233055 | 0.600716 | 0.0010 |
| 9 | 10 | 1.239771 | 0.576730 | 1.286306 | 0.571886 | 0.0010 |
| 10 | 11 | 1.161845 | 0.609200 | 1.285128 | 0.582438 | 0.0002 |
| 11 | 12 | 1.162829 | 0.608392 | 1.396613 | 0.533823 | 0.0002 |
| 12 | 13 | 1.155751 | 0.611703 | 1.431812 | 0.529301 | 0.0002 |
| 13 | 14 | 1.143228 | 0.613965 | 1.419468 | 0.526663 | 0.0002 |
| 14 | 15 | 1.140438 | 0.617075 | 1.400278 | 0.546637 | 0.0002 |
# Create a DataFrame from the history object
history_df = pd.DataFrame(history.history)
# Plot the training and validation loss
plt.figure(figsize=(9, 5))
values = history_df['accuracy']
epochs = range(1, len(values) + 1)
plt.plot(epochs, history_df['loss'], 'bo', label='Training loss')
plt.plot(epochs, history_df['val_loss'], 'ro', label='Validation loss')
plt.xlabel('Epochs')
plt.xticks(epochs)
plt.ylabel('Loss')
plt.legend()
plt.title('Training and validation loss')
plt.show()
# Plot the training and validation accuracy
plt.figure(figsize=(9, 5))
plt.plot(epochs, history_df['accuracy'], 'bo', label='Training accuracy')
plt.plot(epochs, history_df['val_accuracy'], 'ro', label='Validation accuracy')
plt.xlabel('Epochs')
plt.xticks(epochs)
plt.ylabel('Accuracy')
plt.legend()
plt.title('Training and validation accuracy')
plt.show()
from tensorflow.keras.applications import InceptionV3
inception_model = InceptionV3(weights='imagenet', include_top=False, input_shape=(150, 150, 3))
# Freeze the base model
inception_model.trainable = False
# Add custom layers on top of the base model
x = inception_model.output
x = GlobalAveragePooling2D()(x)
x = Dense(512, activation='relu')(x)
predictions = Dense(10, activation='softmax')(x)
# Create the model
model = Model(inputs=inception_model.input, outputs=predictions)
# Compile the model
model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])
inception_callbacks = [
callbacks.ModelCheckpoint(filepath='./models/newer/inception.h5', save_best_only=True),
callbacks.EarlyStopping(monitor='val_loss', patience=10, verbose=1),
callbacks.ReduceLROnPlateau(monitor='val_loss', factor=0.2, patience=5, verbose=1, min_lr=1e-5)
]
# Training the model
history = model.fit(train_generator, validation_data=valid_generator, epochs=10, callbacks=inception_callbacks)
Epoch 1/10 774/774 [==============================] - 306s 391ms/step - loss: 0.3652 - accuracy: 0.8914 - val_loss: 0.1458 - val_accuracy: 0.9516 - lr: 0.0010 Epoch 2/10 774/774 [==============================] - 305s 394ms/step - loss: 0.2088 - accuracy: 0.9336 - val_loss: 0.1328 - val_accuracy: 0.9587 - lr: 0.0010 Epoch 3/10 774/774 [==============================] - 306s 395ms/step - loss: 0.1767 - accuracy: 0.9420 - val_loss: 0.1056 - val_accuracy: 0.9653 - lr: 0.0010 Epoch 4/10 774/774 [==============================] - 305s 394ms/step - loss: 0.1616 - accuracy: 0.9458 - val_loss: 0.0891 - val_accuracy: 0.9708 - lr: 0.0010 Epoch 5/10 774/774 [==============================] - 305s 394ms/step - loss: 0.1588 - accuracy: 0.9487 - val_loss: 0.0907 - val_accuracy: 0.9714 - lr: 0.0010 Epoch 6/10 774/774 [==============================] - 303s 391ms/step - loss: 0.1503 - accuracy: 0.9502 - val_loss: 0.0718 - val_accuracy: 0.9763 - lr: 0.0010 Epoch 7/10 774/774 [==============================] - 303s 391ms/step - loss: 0.1387 - accuracy: 0.9542 - val_loss: 0.0725 - val_accuracy: 0.9768 - lr: 0.0010 Epoch 8/10 774/774 [==============================] - 386s 499ms/step - loss: 0.1397 - accuracy: 0.9544 - val_loss: 0.0598 - val_accuracy: 0.9808 - lr: 0.0010 Epoch 9/10 774/774 [==============================] - 434s 561ms/step - loss: 0.1338 - accuracy: 0.9554 - val_loss: 0.0574 - val_accuracy: 0.9804 - lr: 0.0010 Epoch 10/10 774/774 [==============================] - 321s 415ms/step - loss: 0.1302 - accuracy: 0.9582 - val_loss: 0.0643 - val_accuracy: 0.9780 - lr: 0.0010
history_df = pd.DataFrame(history.history)
history_df.insert(0, 'epoch', range(1, len(history_df) + 1))
history_df
| epoch | loss | accuracy | val_loss | val_accuracy | lr | |
|---|---|---|---|---|---|---|
| 0 | 1 | 0.365223 | 0.891366 | 0.145790 | 0.951573 | 0.001 |
| 1 | 2 | 0.208753 | 0.933608 | 0.132835 | 0.958734 | 0.001 |
| 2 | 3 | 0.176746 | 0.942048 | 0.105626 | 0.965329 | 0.001 |
| 3 | 4 | 0.161572 | 0.945844 | 0.089074 | 0.970793 | 0.001 |
| 4 | 5 | 0.158773 | 0.948712 | 0.090716 | 0.971359 | 0.001 |
| 5 | 6 | 0.150257 | 0.950246 | 0.071814 | 0.976258 | 0.001 |
| 6 | 7 | 0.138736 | 0.954164 | 0.072514 | 0.976823 | 0.001 |
| 7 | 8 | 0.139679 | 0.954366 | 0.059811 | 0.980780 | 0.001 |
| 8 | 9 | 0.133834 | 0.955416 | 0.057398 | 0.980403 | 0.001 |
| 9 | 10 | 0.130176 | 0.958162 | 0.064259 | 0.977954 | 0.001 |
# Create a DataFrame from the history object
history_df = pd.DataFrame(history.history)
# Plot the training and validation loss
plt.figure(figsize=(9, 5))
values = history_df['accuracy']
epochs = range(1, len(values) + 1)
plt.plot(epochs, history_df['loss'], 'bo', label='Training loss')
plt.plot(epochs, history_df['val_loss'], 'ro', label='Validation loss')
plt.xlabel('Epochs')
plt.xticks(epochs)
plt.ylabel('Loss')
plt.legend()
plt.title('Training and validation loss')
plt.show()
# Plot the training and validation accuracy
plt.figure(figsize=(9, 5))
plt.plot(epochs, history_df['accuracy'], 'bo', label='Training accuracy')
plt.plot(epochs, history_df['val_accuracy'], 'ro', label='Validation accuracy')
plt.xlabel('Epochs')
plt.xticks(epochs)
plt.ylabel('Accuracy')
plt.legend()
plt.title('Training and validation accuracy')
plt.show()
# evaluate the model
model.evaluate(test_generator)
166/166 [==============================] - 11s 67ms/step - loss: 0.0688 - accuracy: 0.9782
[0.06876641511917114, 0.9781585335731506]
from tensorflow.keras.applications import Xception
efficient_model = Xception(weights='imagenet', include_top=False, input_shape=(150, 150, 3))
Downloading data from https://storage.googleapis.com/tensorflow/keras-applications/xception/xception_weights_tf_dim_ordering_tf_kernels_notop.h5 83683744/83683744 [==============================] - 26s 0us/step
# Freeze the base model
efficient_model.trainable = False
# Add custom layers on top of the base model
x = efficient_model.output
x = GlobalAveragePooling2D()(x)
x = Dense(512, activation='relu')(x)
predictions = Dense(10, activation='softmax')(x)
# Create the model
model = Model(inputs=efficient_model.input, outputs=predictions)
# Compile the model
model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])
efficient_callbacks = [
callbacks.ModelCheckpoint(filepath='./models/newer/efficient.h5', save_best_only=True),
callbacks.EarlyStopping(monitor='val_loss', patience=10, verbose=1),
callbacks.ReduceLROnPlateau(monitor='val_loss', factor=0.2, patience=5, verbose=1, min_lr=1e-5)
]
# Training the model
history = model.fit(train_generator, validation_data=valid_generator, epochs=15, callbacks=efficient_callbacks)
Epoch 1/15 774/774 [==============================] - 316s 406ms/step - loss: 0.2653 - accuracy: 0.9118 - val_loss: 0.1146 - val_accuracy: 0.9617 - lr: 0.0010 Epoch 2/15 774/774 [==============================] - 307s 397ms/step - loss: 0.1586 - accuracy: 0.9480 - val_loss: 0.0836 - val_accuracy: 0.9714 - lr: 0.0010 Epoch 3/15 774/774 [==============================] - 310s 400ms/step - loss: 0.1366 - accuracy: 0.9559 - val_loss: 0.0994 - val_accuracy: 0.9650 - lr: 0.0010 Epoch 4/15 774/774 [==============================] - 314s 406ms/step - loss: 0.1243 - accuracy: 0.9596 - val_loss: 0.0797 - val_accuracy: 0.9749 - lr: 0.0010 Epoch 5/15 774/774 [==============================] - 309s 399ms/step - loss: 0.1154 - accuracy: 0.9607 - val_loss: 0.0854 - val_accuracy: 0.9702 - lr: 0.0010 Epoch 6/15 774/774 [==============================] - 323s 417ms/step - loss: 0.1054 - accuracy: 0.9641 - val_loss: 0.0850 - val_accuracy: 0.9714 - lr: 0.0010 Epoch 7/15 774/774 [==============================] - 339s 438ms/step - loss: 0.1044 - accuracy: 0.9651 - val_loss: 0.0915 - val_accuracy: 0.9689 - lr: 0.0010 Epoch 8/15 774/774 [==============================] - 363s 469ms/step - loss: 0.1003 - accuracy: 0.9665 - val_loss: 0.0498 - val_accuracy: 0.9834 - lr: 0.0010 Epoch 9/15 774/774 [==============================] - 306s 396ms/step - loss: 0.0977 - accuracy: 0.9684 - val_loss: 0.0588 - val_accuracy: 0.9810 - lr: 0.0010 Epoch 10/15 774/774 [==============================] - 305s 395ms/step - loss: 0.0941 - accuracy: 0.9693 - val_loss: 0.0511 - val_accuracy: 0.9838 - lr: 0.0010 Epoch 11/15 774/774 [==============================] - 308s 398ms/step - loss: 0.0851 - accuracy: 0.9722 - val_loss: 0.0524 - val_accuracy: 0.9842 - lr: 0.0010 Epoch 12/15 774/774 [==============================] - 312s 403ms/step - loss: 0.0899 - accuracy: 0.9713 - val_loss: 0.0685 - val_accuracy: 0.9785 - lr: 0.0010 Epoch 13/15 774/774 [==============================] - 308s 397ms/step - loss: 0.0880 - accuracy: 0.9710 - val_loss: 0.0465 - val_accuracy: 0.9845 - lr: 0.0010 Epoch 14/15 774/774 [==============================] - 311s 401ms/step - loss: 0.0801 - accuracy: 0.9737 - val_loss: 0.0503 - val_accuracy: 0.9845 - lr: 0.0010 Epoch 15/15 774/774 [==============================] - 311s 402ms/step - loss: 0.0774 - accuracy: 0.9751 - val_loss: 0.0478 - val_accuracy: 0.9827 - lr: 0.0010
history_df = pd.DataFrame(history.history)
history_df.insert(0, 'epoch', range(1, len(history_df) + 1))
history_df
| epoch | loss | accuracy | val_loss | val_accuracy | lr | |
|---|---|---|---|---|---|---|
| 0 | 1 | 0.265340 | 0.911841 | 0.114605 | 0.961749 | 0.001 |
| 1 | 2 | 0.158584 | 0.948025 | 0.083582 | 0.971359 | 0.001 |
| 2 | 3 | 0.136570 | 0.955900 | 0.099449 | 0.964952 | 0.001 |
| 3 | 4 | 0.124294 | 0.959575 | 0.079673 | 0.974939 | 0.001 |
| 4 | 5 | 0.115392 | 0.960706 | 0.085360 | 0.970228 | 0.001 |
| 5 | 6 | 0.105406 | 0.964058 | 0.084982 | 0.971359 | 0.001 |
| 6 | 7 | 0.104378 | 0.965148 | 0.091515 | 0.968909 | 0.001 |
| 7 | 8 | 0.100327 | 0.966481 | 0.049812 | 0.983418 | 0.001 |
| 8 | 9 | 0.097743 | 0.968379 | 0.058797 | 0.980969 | 0.001 |
| 9 | 10 | 0.094106 | 0.969308 | 0.051137 | 0.983795 | 0.001 |
| 10 | 11 | 0.085105 | 0.972175 | 0.052445 | 0.984172 | 0.001 |
| 11 | 12 | 0.089946 | 0.971287 | 0.068457 | 0.978519 | 0.001 |
| 12 | 13 | 0.087987 | 0.971044 | 0.046454 | 0.984549 | 0.001 |
| 13 | 14 | 0.080096 | 0.973669 | 0.050293 | 0.984549 | 0.001 |
| 14 | 15 | 0.077437 | 0.975083 | 0.047846 | 0.982664 | 0.001 |
# Create a DataFrame from the history object
history_df = pd.DataFrame(history.history)
# Plot the training and validation loss
plt.figure(figsize=(9, 5))
values = history_df['accuracy']
epochs = range(1, len(values) + 1)
plt.plot(epochs, history_df['loss'], 'bo', label='Training loss')
plt.plot(epochs, history_df['val_loss'], 'ro', label='Validation loss')
plt.xlabel('Epochs')
plt.xticks(epochs)
plt.ylabel('Loss')
plt.legend()
plt.title('Training and validation loss')
plt.show()
# Plot the training and validation accuracy
plt.figure(figsize=(9, 5))
plt.plot(epochs, history_df['accuracy'], 'bo', label='Training accuracy')
plt.plot(epochs, history_df['val_accuracy'], 'ro', label='Validation accuracy')
plt.xlabel('Epochs')
plt.xticks(epochs)
plt.ylabel('Accuracy')
plt.legend()
plt.title('Training and validation accuracy')
plt.show()
model.evaluate(test_generator)
166/166 [==============================] - 10s 61ms/step - loss: 0.0504 - accuracy: 0.9810
[0.050435829907655716, 0.9809828400611877]